using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Text;
using System.Web;
using System.Xml;
using Graffiti.Core;

namespace Graffiti.Slide.Show
{
    /// <summary>
    /// This plugin looks for photos on the web server
    /// </summary>
    internal class FolderDataHandler
    {

        #region Private Fields

        private string _rootFolderPath = null;
        private Macros _macros = null;
        private HttpContext _context = null;
        private List<string> _validFileExtensions = null;
        private int _startAlbum = -1;
        private string _slideTransition = "";
        private bool _createThumbnails = false;
        #endregion

        #region Constructor
        internal FolderDataHandler(HttpContext context, string rootFolderPath, int startAlbum, string slideTransition)
        {
            this._context = context;
            this._rootFolderPath = rootFolderPath;
            this._startAlbum = startAlbum;
            this._slideTransition = slideTransition;
            this._macros = new Macros();

            this._validFileExtensions = new List<string>();
            this._validFileExtensions.Add(".jpg");
            this._validFileExtensions.Add(".jpeg");
            this._validFileExtensions.Add(".png");

        }
        #endregion

        #region Internal Methodws

        internal void ProcessRequest()
        {

            List<ImageFolder> albums = GetAlbums();

            if (albums == null || albums.Count == 0)
                return;

            _context.Response.Clear();
            _context.Response.Cache.SetCacheability(HttpCacheability.Public);

            StringWriter sw = new StringWriter();
            sw.WriteLine("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>");
            XmlTextWriter writer = new XmlTextWriter(sw);

            writer.WriteStartElement("data");

            if (this._startAlbum >= 0)
                writer.WriteAttributeString("startalbumindex", this._startAlbum.ToString());
                
            if (string.IsNullOrEmpty(this._slideTransition))
                writer.WriteAttributeString("transition", "CrossFadeTransition");
            else
                writer.WriteAttributeString("transition", this._slideTransition);

            foreach (ImageFolder album in albums)
            {
                if (album.ImageFiles != null && album.ImageFiles.Count > 0)
                {
                    writer.WriteStartElement("album");
                    writer.WriteAttributeString("title", album.Title.Replace('_', ' '));
                    if (!string.IsNullOrEmpty(album.Description))
                        writer.WriteAttributeString("description", album.Description);
                    writer.WriteAttributeString("image", album.ImageFiles[0].FileURL);

                    foreach (ImageFile file in album.ImageFiles)
                    {
                        writer.WriteStartElement("slide");
                        writer.WriteAttributeString("title", file.Title);
                        writer.WriteAttributeString("image", file.FileURL);
                        //if (!string.IsNullOrEmpty(file.ThumbnailFileURL))
                        //    writer.WriteAttributeString("thumbnail", file.ThumbnailFileURL);
                        writer.WriteEndElement(); // End slide
                    }

                    writer.WriteEndElement(); // End album
                }
            }

            writer.WriteEndElement(); // End data

            // save XML into response
            _context.Response.ContentEncoding = System.Text.Encoding.UTF8;
            _context.Response.ContentType = "text/xml";
            _context.Response.Write(sw.ToString());
            _context.Response.End();

        }

        #endregion

        #region Private Methods

        private List<ImageFolder> GetAlbums()
        {
            List<ImageFolder> albums = ZCache.Get<List<ImageFolder>>("slideshowplugin-albums");
            if (albums == null)
            {
                albums = new List<ImageFolder>();

                if (_rootFolderPath.StartsWith("~"))
                {
                    _rootFolderPath = _context.Server.MapPath(_rootFolderPath);
                }

                DirectoryInfo dirInfo = new DirectoryInfo(this._rootFolderPath);

                // Look to see if there are any imgage files in the root folder
                // If so we'll add these to their own album
                FileInfo[] files = dirInfo.GetFiles("*.*", SearchOption.TopDirectoryOnly);
                if (files != null && files.Length > 0)
                {
                    List<ImageFile> imageFiles = AddFiles(files);
                    albums.Add(new ImageFolder(dirInfo.Name, GetAlbumDescription(dirInfo), imageFiles));
                }

                DirectoryInfo[] subFolders = dirInfo.GetDirectories();
                foreach (DirectoryInfo dir in subFolders)
                {
                    files = dir.GetFiles("*.*", SearchOption.TopDirectoryOnly);
                    if (files != null && files.Length > 0)
                    {
                        List<ImageFile> imageFiles = AddFiles(files);
                        albums.Add(new ImageFolder(dir.Name, GetAlbumDescription(dir), imageFiles));
                    }
                }

                ZCache.InsertCache("slideshowplugin-albums", albums, 60);
            }

            return albums;
        }

        private List<ImageFile> AddFiles(FileInfo[] files)
        {
            List<ImageFile> imageFiles = new List<ImageFile>();
            foreach (FileInfo file in files)
            {
                if (!string.IsNullOrEmpty(file.Name) && !string.IsNullOrEmpty(file.Extension) && _validFileExtensions.Contains(file.Extension.ToLower()))
                {
                    try
                    {
                        
                        ImageFile image = new ImageFile();
                        int len = Convert.ToInt32(file.Name.Length - (file.Extension.Length));
                        string title = file.Name.Substring(0, len);
                        image.Title = title.Trim().Replace('_', ' ');
                        image.FileURL = _macros.FullUrl(MapUrl(file.FullName));

                        // Check for thumbnail
                        //if (this._createThumbnails)
                        //    image.ThumbnailFileURL = GetThumbnailFilePath(file);

                        imageFiles.Add(image);
                    }
                    catch { }
                }
            }
            return imageFiles;
        }

        private string GetThumbnailFilePath(FileInfo file)
        {
            string thumbDirPath = Path.Combine(file.DirectoryName, "thumbnails");
            if (!Directory.Exists(thumbDirPath))
                Directory.CreateDirectory(thumbDirPath);

            string thumbFilePath = Path.Combine(thumbDirPath, file.Name);

            if (File.Exists(thumbFilePath))
            {
                return thumbFilePath;
            }
            else if (this._createThumbnails)
            {
                try
                {
                    using (Stream sourceStream = File.OpenRead(file.FullName))
                    {
                        using (Stream imageStream = ResizeImage(sourceStream, 120, 150))
                        {
                            imageStream.Position = 0;
                            using (FileStream outStream = File.OpenWrite(thumbFilePath))
                            {
                                byte[] buffer = new byte[imageStream.Length > 65536 ? 65536 : imageStream.Length];
                                int position = 0;
                                while (position < imageStream.Length)
                                {
                                    int read = imageStream.Read(buffer, 0, buffer.Length);
                                    outStream.Write(buffer, 0, read);
                                    position += read;
                                }

                                outStream.Flush();
                            }
                            imageStream.Close();
                        }
                        sourceStream.Close();
                    }

                    return thumbFilePath;
                }
                catch (Exception ex)
                {
                    Log.Warn("Thumbnail image could not be created", "An error occured in the Slide.Show2 Photo Gallery plugin while trying to generate a thumbnail image. Exception message was: {0}", ex.Message);
                }
            }

            return null;
        }

        private MemoryStream ResizeImage(Stream stream, int height, int width)
        {

            Bitmap bitmapOriginal = new Bitmap(stream);
            Bitmap bitmapResize = bitmapOriginal;
            MemoryStream returnStream = new MemoryStream();
            float scale;

            if ((bitmapOriginal.Height > height) || (bitmapOriginal.Width > width))
            {

                // Get the scale
                if (bitmapOriginal.Width < bitmapOriginal.Height)
                    scale = (float)height / (float)bitmapOriginal.Height;
                else
                    scale = (float)width / (float)bitmapOriginal.Width;

                int newWidth = (int)(scale * bitmapOriginal.Width);
                int newHeight = (int)(scale * bitmapOriginal.Height);

                bitmapResize = new Bitmap(newWidth, newHeight);
                using (Graphics g = Graphics.FromImage(bitmapResize))
                {
                    g.Clear(Color.Transparent);
                    g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
                    g.DrawImage(bitmapOriginal, 0, 0, newWidth, newHeight);
                }
            }

            ImageCodecInfo codecInfo = null;
            foreach (ImageCodecInfo ci in ImageCodecInfo.GetImageEncoders())
            {

                if (ci.FormatID == bitmapOriginal.RawFormat.Guid)
                {
                    codecInfo = ci;
                    break;
                }
            }

            EncoderParameters encoderParameters = new EncoderParameters(1);
            encoderParameters.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 75L);

            bitmapResize.Save(returnStream, codecInfo, encoderParameters);

            if (bitmapResize != bitmapOriginal)
                bitmapResize.Dispose();

            bitmapOriginal.Dispose();

            return returnStream;
        }

        private string GetAlbumDescription(DirectoryInfo folder)
        {
            string descFile = Path.Combine(folder.FullName, "album.txt");
            if (File.Exists(descFile))
            {
                return File.ReadAllText(descFile);
            }

            return string.Empty;
        }

        private string MapUrl(string path)
        {
            string appPath = _context.Server.MapPath("~");
            return string.Concat(_context.Request.ApplicationPath, path.Replace(appPath, "").Replace(Path.DirectorySeparatorChar, '/'));
        }

        #endregion

    }
}
